package com.yeskery.nut.bind.handler;

import com.yeskery.nut.annotation.web.RequestBody;
import com.yeskery.nut.bean.NoSuchBeanException;
import com.yeskery.nut.bind.AnnotationBindObject;
import com.yeskery.nut.bind.BindObject;
import com.yeskery.nut.bind.MethodParamHandler;
import com.yeskery.nut.core.Execution;
import com.yeskery.nut.core.MediaType;
import com.yeskery.nut.core.NutException;
import com.yeskery.nut.core.Request;
import com.yeskery.nut.extend.responsive.*;
import com.yeskery.nut.scan.controller.AnnotationRequestMethodAttributes;
import com.yeskery.nut.util.ReflectUtils;
import com.yeskery.nut.util.ResourceUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Parameter;

/**
 * RequestBody方法参数对象处理接口
 * @author sprout
 * 2022-06-11 15:58
 */
public class RequestBodyMethodParamHandler implements MethodParamHandler {

    @Override
    public AnnotationBindObject handle(AnnotationRequestMethodAttributes attributes, Annotation annotation, Parameter parameter, Request request, Execution execution) {
        Object object = getResourceRequestBodyObject(parameter, request);
        if (object != null) {
            return new AnnotationBindObject(new BindObject(object, false), RequestBody.class,
                    ((RequestBody) annotation).required(), null);
        }
        Responsive responsive;
        String[] consumes;
        if ((consumes = attributes.getConsumes()) != null && consumes.length > 0 && MediaType.APPLICATION_XML.getValue().equals(consumes[0])) {
            try {
                responsive = execution.getBindContext().getObject(XmlResponsive.class);
            } catch (NoSuchBeanException e) {
                throw new NutException("Use Annotation [@RequestBody] And Set Request Consume[" + MediaType.APPLICATION_XML.getValue()
                        + "], But Unable Find Plugin[" + XmlResponsivePlugin.class.getName() + "]");
            }
        } else {
            try {
                responsive = execution.getBindContext().getObject(JsonResponsive.class);
            } catch (NoSuchBeanException e) {
                throw new NutException("Use Annotation [@RequestBody] And Set Request Consume[" + MediaType.APPLICATION_JSON.getValue()
                        + "], But Unable Find Plugin[" + JsonResponsivePlugin.class.getName() + "]");
            }
        }

        Object data = responsive.getBody(parameter.getType());
        boolean isEmpty = data == null;
        if (isEmpty) {
            Constructor<?> constructor = ReflectUtils.getBeanFitConstructor(parameter.getType());
            if (constructor.getParameterCount() != 0) {
                throw new NutException("@RequestBody Parameter name[" + parameter.getName() + "], type["
                        + parameter.getType().getName() + "], Need No Param Constructor.");
            }
            try {
                data = constructor.newInstance();
            } catch (Exception e) {
                throw new NutException("@RequestBody Parameter name[" + parameter.getName() + "], type["
                        + parameter.getType().getName() + "], Create Instance Fail.", e);
            }
        }
        return new AnnotationBindObject(new BindObject(data, isEmpty), RequestBody.class,
                ((RequestBody) annotation).required(), null);
    }

    /**
     * 获取资源对象
     * @param parameter 参数对象
     * @param request 请求对象
     * @return 资源对象
     */
    private Object getResourceRequestBodyObject(Parameter parameter, Request request) {
        try {
            return ResourceUtils.createInputStreamResourceObject(parameter.getType(), request.getBody());
        } catch (IllegalArgumentException e) {
            return null;
        }
    }
}
